
/* <primitive: 60>
 * <Object> basicAt: <SmallInteger>
 * Answer the indexed field of the receiever at the rank indicated by the argument.  Fail if the argument is not a SmallInteger or out-of-bounds.
 * Essential.
 */
void primAt()
{
	int i,o,fmt,v,f,namedSize,s,nWords,nBytes;
	
	o = peek(1);
	i = unpackSmInt(peek(0));
	if(!success) return;
	
	fmt = formatOf(o);
	
	if(fmt == 0 || fmt == 1){ //no fields, named pointers => fail
		success=0;
	}else if(fmt == 2){ //indexed pointers
		if( i>=1 && i<=sizeOf(o) )
		{
			popNandPush(2, slotOf(o,i) );
		}
		else 
			success=0;
	}else if(fmt == 3 || fmt == 4){ //named and indexed pointers (strong or weak)
		namedSize = instSizeOf(o);
		s = sizeOf(o) - namedSize;
		if( i>=1 && i<=s )
			popNandPush(2, slotOf(o,i+namedSize) );
		else
			success=0;
	}else if(fmt == 6){ //indexed words 
		if( i>=1 && i <= sizeOf(o) )
			popNandPush(2, packPos32(slotOf(o,i)));
		else
			success=0;
	}else if( (fmt >= 8 && fmt <= 11) || (fmt >= 12 && fmt <=15) ){ //indexed bytes
		nWords = sizeOf(o);
		nBytes = (nWords*4) - (fmt&3);
		
		if( i>=1 && i<=nBytes )
			popNandPush(2, packSmInt(byteSlotOf(o,i)));
		else
			success=0;
	}else{
		printf("%d", fmt);
		PANIC("other at:");
	}
}

/* <primitive: 61>
 * <Object> basicAt: <SmallInteger> put: <Object>
 * Stored the 2nd argument in the indexed field of the receiever at the rank indicated by the 1st argument.  Answer the stored value.  Fail if the argument is not a SmallInteger or out-of-bounds.
 * Essential.
 */
void primAtPut()
{
	int i,o,fmt,v,f,namedSize,s,nWords,nBytes;
	
	o = peek(2);
	i = unpackSmInt(peek(1));
	v = peek(0);
	if(!success)return;
	
	fmt = formatOf(o);
	
	if(fmt == 0 || fmt == 1){ //no fields, named pointers => fail
		success=0;
	}else if(fmt == 2){ //indexed pointers
		if( i>=1 && i<=sizeOf(o) )
		{
			setSlotOf(o,i,v);
			popNandPush(3, v);
		}
		else
			success=0;
	}else if(fmt == 3 || fmt == 4){ //named and indexed pointers
		namedSize = instSizeOf(o);
		s = sizeOf(o) - namedSize;
		
		if( i>=1 && i<=s )
		{
			setSlotOf(o,i+namedSize,v);
			popNandPush(3, v);
		}
		else
			success=0;
	}else if(fmt == 6){ //indexed words	
		if( i>=1 && i <= sizeOf(o) )
		{
			int raw = unpackPos32(v);
			if(success) {
				setSlotOf(o,i,raw);
				popNandPush(3, v);
			}
		}
		else
			success=0;
	}else if( (fmt >= 8 && fmt <= 11) || (fmt >= 12 && fmt <=15) ){ //indexed bytes
		
		nWords = sizeOf(o);
		nBytes = (nWords*4) - (fmt&3);
		
		if( i>=1 && i<=nBytes ){
			int raw = unpackSmInt(v);
			if( raw<0 || raw>255 ) success=0;
			if(success){
				setByteSlotOf(o,i,raw);
				popNandPush(3, v);
			}
		}
		else
			success=0;
	}else{
		PANIC("other at:put:");
	}
}

/* <primitive: 62>
 * <Object> basicSize
 * Answer the number of indexed fields in the reciever.
 * Essential.
 */
void primSize() //BOGUS Is this supposed to fail if rcvr is not indexable?  Or return 0?
{
	int o, fmt, c, i, nWords, nBytes, f, s, namedSize;

	o = peek(0);

	if( isSmInt(o) ) { 
		popNandPush(1, packSmInt(0));
		return;
	}
	
	fmt = formatOf(o);
			
	if(fmt == 0 || fmt == 1){ //no fields, named pointers
		popNandPush(1, packSmInt(0));
	}else if(fmt == 2){ //indexed pointers
		popNandPush(1, packSmInt(sizeOf(o)));
	}else if(fmt==3 || fmt==4 ){ //named and indexed pointers
		//count only the indexed portion        
		popNandPush(1, packSmInt( sizeOf(o) - instSizeOf(o) ) );
	}else if(fmt == 6){ //indexed words
		popNandPush(1, packSmInt(sizeOf(o)));
	}else if(fmt<=11){ //indexed bytes
		nWords = sizeOf(o);
		nBytes = (nWords*4) - (fmt&3);
		popNandPush(1, packSmInt(nBytes) );		
	}else if(fmt>11){ //compiled method
		//N.B., size considers the whole thing (even header and literals) to be bytes
		//weird, because this means the size of pointers is known to the image side
		//though it really shouldn't be
		nBytes = (sizeOf(o)*4) - (fmt&3);
		popNandPush(1, packSmInt(nBytes) );	
	}else{
		printFullObject(o);
		PANIC("other size of");
	}
}

/* <primitive: 63>
 * <ByteString> at: <SmallInteger>
 * Like basicAt:, but perform the convertion to a Character.
 * Essential. (though it shouldn't be)
 */
void primStringAt()
{
	//BOGUS should check object format
	int o,i;
	o = peek(1);
	i = unpackSmInt(peek(0));
	if(!success) return;
	
	popNandPush( 2, slotOf( CharacterTable, byteSlotOf(o,i)+1 ) );
}

/* <primitive: 64>
 * <ByteString> at: <SmallInteger>
 * Like basicAt:put:, but perform the convertion to a Character.
 * Essential.  (though it shouldn't be)
 */
void primStringAtPut()
{
	//BOGUS should check object format
	int o,i,v;
	o = peek(2);
	i = unpackSmInt(peek(1));
	v = peek(0);
	
	if(!success)return;
	
	if( classOf(v)!=Character ) success=0;
	else
	{
		int raw = unpackSmInt(slotOf(v,1));
		if(raw<0 || raw>255) success=0;
		if(success)
		{
			setByteSlotOf(o, i, raw);
			popNandPush(3, v);
		}
	}
}

void primNext(){success=0;} //65, optional
void primNextPut(){success=0;} //66, optional
void primAtEnd(){success=0;} //67, optional

/* <primitive: 68>
 * CompiledMethod objectAt: <SmallInteger>
 * Operates on the pointer fields (header+literals) of a CompiledMethod.
 * Essential.
 */
void primObjectAt()
{
	int i,o,fmt,v,f,header,nWords;
	
	o = peek(1);
	i = unpackSmInt(peek(0));
	
	if(!success) return;
	
	fmt = formatOf(o);
	
	if(fmt >= 12 && fmt <= 15){
		
		header = slotOf(o, 1);
		nWords = (header>>10)&255; //number of literals
		nWords += 1;
		
		if( i>=1 && i<=nWords )
		{
			popNandPush( 2, slotOf(o,i) );
		}
		else
			success=0;
	}
	else{
		printFullObject(o);
		PANIC("bad format for objectAt:");
	}
}

/* <primitive: 69>
 * CompiledMethod objectAt: <SmallInteger> put: <Object>
 * Operates on the pointer fields (header+literals) of a CompiledMethod.
 * Essential.
 */
void primObjectAtPut()
{
	int i,o,fmt,v,f,header,nWords;
	
	o = peek(2);
	i = unpackSmInt(peek(1));
	v = peek(0);
	
	if(!success) return;
	
	fmt = formatOf(o);
	
	if(fmt >= 12 && fmt <= 15){
		
		header = slotOf(o, 1);
		nWords = (header>>10)&255; //number of literals
		nWords += 1;
		
		if( i==1 )
		{
			PANIC("Attempt to change header of a CompiledMethod");
		}
		
		if( i>=1 && i<=nWords )
		{
			setSlotOf(o,i,v);
			popNandPush(3, v);
		}
		else
			success=0;
	}
}

void primSignedShortAt()
{
	int o = peek(1);
	int i = unpackSmInt(peek(0));
	
	int fmt = formatOf(o);
	
	if(fmt==6){}
	else if(fmt >= 8 && fmt <= 11) {}
	else success=0;
	
	if(success)
	{
		int size = sizeOf(o) * 2; //BOGUS, not really correct for byte objects
		
		if( i>=1 && i<=size )
		{
			short val = *(short*)(o+4+(2*(i-1)));
			popNandPush(argumentCount+1, packSmInt((int)val));
		}
		else
			success=0;
	}
}
